package ws.com.controller;

import ws.com.activeMQ.product.Product;
import ws.com.config.MyWebSocketConf;
import ws.com.pojo.WsDTO;
import ws.com.utils.BeanUtils;
import ws.com.activeMQ.MqConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import ws.com.mapper.BarrageMapper;
import ws.com.pojo.Barrage;
import ws.com.pojo.WsResponse;

import javax.annotation.Resource;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 需要把websocket包下的文件作为独立的程序
 */
@Slf4j
@Component
@ServerEndpoint(value = "/ws/{vid}" ,configurator = MyWebSocketConf.class , encoders = {WsResponse.class})
public class WebSocketController {

    private static Product product;

    @Autowired
    public void setProduct(Product product){
        WebSocketController.product = product;
    }

    private static BarrageMapper barrageMapper;

    @Resource
    public void setBarrageMapper(BarrageMapper barrageMapper){
        WebSocketController.barrageMapper = barrageMapper;
    }

    public static Map<String , Set<Session>> video = new ConcurrentHashMap<>();

    @OnOpen
    public void onOpen(@PathParam("vid") String vid , Session session){

        if(!video.containsKey(vid)){
            Set<Session> currentWatchVideo = new HashSet<>();
            currentWatchVideo.add(session);
            video.put(vid,currentWatchVideo);
        }else{
            video.get(vid).add(session);
        }

        WsDTO wsDTO = new WsDTO();
        wsDTO.setVid(vid);
        wsDTO.setWatchNum(1);
        product.sendMessage(MqConstants.WS_WATCH_COUNT,wsDTO);

    }

    @OnError
    public void onError(Session session , Throwable err){

    }

    @OnClose
    public void onClose(@PathParam("vid") String vid , Session session){

        if(video.containsKey(vid)){
            video.get(vid).remove(session);

            WsDTO wsDTO = new WsDTO();
            wsDTO.setVid(vid);
            wsDTO.setWatchNum(-1);
            product.sendMessage(MqConstants.WS_WATCH_COUNT,wsDTO);
        }
    }

    /**
     * 发送即时弹幕传递到其他人
     * @param vid
     * @param session
     * @param content
     */
    @OnMessage
    public void onMessage(@PathParam("vid") String vid , Session session, String content){
        Barrage barrage = BeanUtils.JSONString2Object(content, Barrage.class);
        if(barrage.getUserId() == null){
            log.info("在{} 时 观看vid为{} 出现未登录发送弹幕情形", LocalDateTime.now().toString(), vid);
            return ;
        }
        try{
            barrageMapper.insert(barrage);
            product.sendMessage(MqConstants.WS_SEND_BARRAGE,content);
        }catch (Exception e){
            log.info("弹幕插入数据库失败,[{}]", e.getMessage());
        }
    }

    /**
     * 统计在线观看人数
     */
    public void countPeople(WsDTO wsDTO){
        Set<Session> sessions = video.get(wsDTO.getVid());

        for(Session session: sessions){
            try {
                session.getBasicRemote().sendObject(WsResponse.countPeople(wsDTO.getWatchNum()));
            } catch (IOException | EncodeException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 发送弹幕 使同时观看同一视频的用户
     * @param barrage
     */
    public void sendBarrage(Barrage barrage){
        Set<Session> sessions = video.get(barrage.getVideoId());

        for(Session session: sessions){
            try {
                session.getBasicRemote().sendObject(WsResponse.sendBarrage(barrage));
            } catch (IOException | EncodeException e) {
                e.printStackTrace();
            }
        }
    }
}
